package com.coszero.utils.device

import android.Manifest
import android.content.Context
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.content.res.Resources
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
import android.os.Build
import android.os.Environment
import android.provider.Settings
import android.telephony.TelephonyManager
import android.text.TextUtils
import android.util.Log
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.coszero.utils.utils.LogX
import java.lang.reflect.Method
import java.net.NetworkInterface
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.util.Collections
import java.util.UUID

/**
 * @author xmqian
 * @version 3
 * @date 2018/5/28
 * @desc 获取手机的信息，包括状态信息
 */
object DeviceInfoGetUtils {
    /**
     * 获取是否存在NavigationBar，是否有虚拟按键
     */
    fun checkDeviceHasNavigationBar(context: Context): Boolean {
        var hasNavigationBar: Boolean = false
        val rs: Resources = context.getResources()
        val id: Int = rs.getIdentifier("config_showNavigationBar", "bool", "android")
        if (id > 0) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
                hasNavigationBar = rs.getBoolean(id)
            }
        }
        try {
            val systemPropertiesClass: Class<*> = Class.forName("android.os.SystemProperties")
            val m: Method = systemPropertiesClass.getMethod("get", String::class.java)
            val navBarOverride: String? =
                m.invoke(systemPropertiesClass, "qemu.hw.mainkeys") as String?
            if ("1" == navBarOverride) {
                hasNavigationBar = false
            } else if ("0" == navBarOverride) {
                hasNavigationBar = true
            }
        } catch (e: Exception) {
        }
        return hasNavigationBar
    }

    val isExitsSdcard: Boolean
        /**
         * 检测Sdcard是否存在
         *
         * @return
         */
        get() {
            if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
                return true
            } else {
                return false
            }
        }

    /**
     * 返回当前屏幕是否为竖屏。
     *
     * @param context
     * @return 当且仅当当前屏幕为竖屏时返回true, 否则返回false。
     */
    fun isScreenOriatationPortrait(context: Context): Boolean {
        return context.getResources()
            .getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT
    }

    /**
     * @param context
     * @return 获取设备唯一标识符
     */
    fun getUniqueId(context: Context): String {
        return md5(getDeviceId(context))
    }

    /**
     *   * deviceID的组成为：渠道标志+识别符来源标志+hash后的终端识别符
     *
     *
     * 渠道标志为：
     * 1，andriod（a）
     *
     *
     * 识别符来源标志：
     * 1， wifi mac地址（wifi）；
     * 2， IMEI（imei）；
     * 3， 序列号（sn）；
     * 4， id：随机码。若前面的都取不到时，则随机生成一个随机码，需要缓存。
     *
     * @param context
     * @return
     */
    private fun getDeviceId(context: Context): String {
        val deviceId: StringBuilder = StringBuilder()
        // 渠道标志
        try {
            //wifi mac地址
            val wifiMac: String = getWifiMac(context)
            if (!TextUtils.isEmpty(wifiMac)) {
                deviceId.append("wifi")
                deviceId.append(wifiMac)
                Log.e("getDeviceId : ", deviceId.toString())
                return deviceId.toString()
            }
            //IMEI（imei）
            val imei: String = getDeviceIMEI(context)
            if (!TextUtils.isEmpty(imei)) {
                deviceId.append("imei")
                deviceId.append(imei)
                Log.e("getDeviceId : ", deviceId.toString())
                return deviceId.toString()
            }
            //序列号（sn）
            val tm: TelephonyManager =
                context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
            var sn: String? = ""
            if (ContextCompat.checkSelfPermission(
                    context,
                    Manifest.permission.READ_PHONE_STATE
                )
                != PackageManager.PERMISSION_GRANTED
            ) {
                sn = tm.getSimSerialNumber()
            } else {
                LogX.e("### No READ_PHONE_STATE Permission")
            }
            if (!TextUtils.isEmpty(sn)) {
                deviceId.append("sn")
                deviceId.append(sn)
                Log.e("getDeviceId : ", deviceId.toString())
                return deviceId.toString()
            }
            var androidId: String? = null
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
                androidId = Settings.Secure.getString(
                    context.getApplicationContext().getContentResolver(),
                    Settings.Secure.ANDROID_ID
                )
            }
            if (!TextUtils.isEmpty(sn)) {
                deviceId.append("androidId")
                deviceId.append(androidId)
                Log.e("getDeviceId : ", deviceId.toString())
                return deviceId.toString()
            }
            //如果上面都没有， 则生成一个id：随机码
            val uuid: String? = getUUID(context)
            if (!TextUtils.isEmpty(uuid)) {
                deviceId.append("uuid")
                deviceId.append(uuid)
                Log.e("getDeviceId : ", deviceId.toString())
                return deviceId.toString()
            }
        } catch (e: Exception) {
            e.printStackTrace()
            deviceId.append("id").append(getUUID(context))
        }
        Log.e("getDeviceId : ", deviceId.toString())
        return deviceId.toString()
    }

    /**
     * 获取手机的IMEI
     *
     * @param context
     * @return
     */
    fun getDeviceIMEI(context: Context): String {
        if (ActivityCompat.checkSelfPermission(
                context,
                Manifest.permission.READ_PHONE_STATE
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            Log.e("getDeviceIMEI", "权限不足")
            return ""
        }
        val tm: TelephonyManager =
            context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        val imei: String = tm.getDeviceId()
        return imei
    }

    /**
     * 获取wifi的mac地址
     *
     * @param context
     * @return
     */
    fun getWifiMac(context: Context): String {
        if (Build.VERSION.SDK_INT >= 23) {
            //6.0以上获取mac地址
            return linkWifiMac
        }
        val wifi: WifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
        val info: WifiInfo = wifi.getConnectionInfo()
        return info.getMacAddress()
    }

    private val linkWifiMac: String
        /**
         * - 需要权限
         * <uses-permission android:name="android.permission.INTERNET"></uses-permission>
         * <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
         *
         * @return 返回已连接wifi的mac地址
         */
        get() {
            try {
                val all: List<NetworkInterface> =
                    Collections.list(NetworkInterface.getNetworkInterfaces())
                for (nif: NetworkInterface in all) {
                    if (!nif.getName().equals("wlan0", ignoreCase = true)) continue
                    val macBytes: ByteArray? = nif.getHardwareAddress()
                    if (macBytes == null) {
                        return ""
                    }
                    val res1: StringBuilder = StringBuilder()
                    for (b: Byte in macBytes) {
                        res1.append(String.format("%02X:", b))
                    }
                    if (res1.length > 0) {
                        res1.deleteCharAt(res1.length - 1)
                    }
                    return res1.toString()
                }
            } catch (ex: Exception) {
            }
            return "02:00:00:00:00:00"
        }


    /**
     * 得到全局唯一UUID
     *
     * @param context
     * @return
     */
    private fun getUUID(context: Context): String? {
        var uuid: String? = ""
        val mShare: SharedPreferences? = context.getSharedPreferences("uuid", 0)
        if (mShare != null) {
            uuid = mShare.getString("uuid", "")
        }
        if (TextUtils.isEmpty(uuid)) {
            uuid = UUID.randomUUID().toString()
            mShare!!.edit().putString("uuid", uuid).commit()
        }
        Log.e("tag", "getUUID : " + uuid)
        return uuid
    }


    /**
     * @param context
     * @return 获得设备SN号(产品序列号)
     */
    fun getSN(context: Context?): String {
        return Build.SERIAL
    }

    /**
     * @param context
     * @return 获得SIM卡SN号(产品序列号)
     */
    fun getSimSN(context: Context): String {
        var id: String? = ""
        if (ActivityCompat.checkSelfPermission(
                context,
                Manifest.permission.READ_PHONE_STATE
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            Log.e("getSimSn", "no permission")
            return ""
        }
        val tm: TelephonyManager =
            context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        id = tm.getSimSerialNumber()
        return if (null == id) "" else id
    }

    /**
     * 获取本地mac地址
     *
     * @param context
     * @return
     */
    fun getLocalMacAddress(context: Context): String {
        val wifiManager: WifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
        val info: WifiInfo = wifiManager.getConnectionInfo()
        return info.getMacAddress()
    }

    /**
     * md5加密
     *
     * @param string
     * @return
     */
    private fun md5(string: String): String {
        val hash: ByteArray
        try {
            hash = MessageDigest.getInstance("MD5").digest(
                string.toByteArray(StandardCharsets.UTF_8)
            )
        } catch (e: NoSuchAlgorithmException) {
            throw RuntimeException("Huh, MD5 should be supported?", e)
        }

        val hex: StringBuilder = StringBuilder(hash.size * 2)
        for (b: Byte in hash) {
            if ((b.toInt() and 0xFF) < 0x10) {
                hex.append("0")
            }
            hex.append(Integer.toHexString(b.toInt() and 0xFF))
        }
        return hex.toString()
    }

    /**
     * 获取AnroidId
     * 替代android 10不能获取IMEI、序列号,(官方建议)
     * 使用AndroidId代替，缺点是应用签署密钥或用户（如系统恢复出产设置）不同返回的Id不同。与实际测试结果相符。
     * 经实际测试：相同签名密钥的不同应用androidId相同，不同签名的应用androidId不同。恢复出产设置或升级系统没测。
     *
     * @param context context
     * @return AnroidId
     */
    fun getAndroidId(context: Context): String {
        var androidId: String = ""
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
            androidId = Settings.Secure.getString(
                context.getApplicationContext().getContentResolver(),
                Settings.Secure.ANDROID_ID
            )
        }
        return androidId
    }

    /**
     * 通过硬件信息拼接，缺点是还是不能保证唯一。
     * 经测试：似乎与方案一比更稳定，不受密钥影响，但非官方建议，没安全感。
     * 替代android 10不能获取IMEI、序列号
     *
     * @param context context
     * @return 拼接的设备id
     * @link(https://blog.csdn.net/yingchengyou/article/details/99717498###)
     */
    private fun makeDeviceId(context: Context): String {
        var androidId: String = ""
        val deviceInfo: String = StringBuilder()
            .append(Build.BOARD).append("#")
            .append(Build.BRAND).append("#") //CPU_ABI，这个值和appp使用的so库是arm64-v8a还是armeabi-v7a有关，舍弃
            //.append(Build.CPU_ABI).append("#")
            .append(Build.DEVICE).append("#")
            .append(Build.DISPLAY).append("#")
            .append(Build.HOST).append("#")
            .append(Build.ID).append("#")
            .append(Build.MANUFACTURER).append("#")
            .append(Build.MODEL).append("#")
            .append(Build.PRODUCT).append("#")
            .append(Build.TAGS).append("#")
            .append(Build.TYPE).append("#")
            .append(Build.USER).append("#")
            .toString()
        //22a49a46-b39e-36d1-b75f-a0d0b9c72d6c
        androidId =
            UUID.nameUUIDFromBytes(deviceInfo.toByteArray(StandardCharsets.UTF_8)).toString()
        return androidId
    }
}
